import type { UserPref } from '../../lib/abstract'
import type { categoryNameType } from '../../types/constants'
import type {
  IPersonalizationItem,
  IPersonalizationItemConfig,
  IRenderFragment,
  MountTarget,
  ResetType,
} from '../../types/interfaces'
import { Toolbar } from '../../components/toolbar'
import { BaseModule } from '../../lib/abstract'
import { LogStyle } from '../../lib/logger'
import { DownloadFileMimeType } from '../../lib/utils/browser/file'
import { ToolKit } from '../../lib/utils/toolkit'
import {
  BUTTON_TEMPLATE,
  BUTTON_TEMPLATE_STYLES,
  CATEGORY_NAME_CONFIG,
  CustomElementStyleId,
  getTitleThemeClassName,
  ITEM_STATE,
  logger,
  PROJECT_PREFIX,
  RESET_TYPES,
} from '../../types/constants'
import { SYMBOLS } from '../../types/interfaces'
import { BackgroundImage } from './personalization/background_image'
import { CustomCss } from './personalization/custom_css'
import { CustomJs } from './personalization/custom_js'
import { ElementHide } from './personalization/element_hide'
import { LoadingPhrases } from './personalization/loading_phrases'
import { LoadingTheme } from './personalization/loading_theme'
import { PageTheme } from './personalization/page_theme'
import { PageNum } from './personalization/search/page_num'
import { PopularLink } from './personalization/search/popular_link'
import { SearchResultColumns } from './personalization/search/result_columns'
import { SearchResultNum } from './personalization/search/result_num'
import { Shortcuts } from './personalization/shortcuts'

export class Personalization extends BaseModule {
  readonly id: string = 'personalization'
  readonly name: string = 'Personalization'
  readonly isInitialized: boolean = false
  readonly supportedPlatforms?: string[] | undefined
  personalizationConfig: UserPref[] = []
  readonly className = 'personalization-settings'
  readonly messageClassName = 'setting-item-message'
  private toolbarInstance: Toolbar | null = null
  private static instance: Personalization

  static async create(): Promise<Personalization> {
    this.instance = new Personalization()
    await this.instance.createConfig()
    return this.instance
  }

  /**
   * 获取初始化配置
   */
  private getItemConfig(): IPersonalizationItemConfig {
    return {
      className: this.className,
      messageName: this.messageClassName,
    }
  }

  /**
   * 创建个性化设置配置
   */
  private async createConfig(): Promise<void> {
    const itemConfig = this.getItemConfig()

    const pageTheme = await PageTheme.create(itemConfig)

    // 自定义样式表需要在页面主题后初始化，这样由于 last 注册导致自定义样式会在主题样式后，便于进行样式覆盖
    this.personalizationConfig = [
      Shortcuts.getInstance(itemConfig),
      pageTheme,
      LoadingTheme.getInstance(itemConfig),
      LoadingPhrases.getInstance(itemConfig),
      BackgroundImage.getInstance(itemConfig),
      ElementHide.getInstance(itemConfig),
      SearchResultColumns.getInstance(itemConfig),
      SearchResultNum.getInstance(itemConfig),
      PopularLink.getInstance(itemConfig),
      PageNum.getInstance(itemConfig),
      CustomCss.getInstance(itemConfig),
      CustomJs.getInstance(itemConfig),
    ].filter(item => item.isEnableModule())

    if (!this.personalizationConfig.length) {
      logger.warn(`[${this.name}] 没有启用的个性化设置`)
    }
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): Personalization {
    if (!Personalization.instance) {
      Personalization.instance = new Personalization()
    }
    return Personalization.instance
  }

  async init(): Promise<void> {
    const initPromises: Promise<void>[] = []

    // 初始化各个设置项
    this.personalizationConfig.forEach((item) => {
      if (typeof item.onInit === 'function') {
        initPromises.push(
          Promise.resolve()
            .then(() => {
              item.onInit!()
              logger.important(`[${this.name}] ${item.id} 应用成功`)
            })
            .catch((error) => {
              logger.error(`[${this.name}] ${item.id} 应用失败:`, error)
              item.initFailed = true
            }),
        )
      }
    })

    try {
      await logger.executeWithLogging('激活个性化', async () => {
        // 并行执行所有初始化
        await Promise.all(initPromises)
      }, {
        collapsed: true,
        color: LogStyle.groupHeader,
      })
    }
    catch (error: any) {
      logger.error(`[${this.name}] 部分个性化应用失败:`, error)
      throw error // 根据业务需求决定是否抛出
    }

    // 执行后续操作
    this.postInit()
  }

  destroy(): Promise<void> | void {

  }

  core(): Promise<void> | void {
  }

  onToggleCallback(_id: string, _checked: boolean): Promise<void> | void {
  }

  applyConfig(_config: any): void {
  }

  handleConfirm?: (() => void | Promise<void>) | undefined

  /**
   * 初始化后处理
   */
  private postInit(): void {
  }

  generateHTML(): string {
    const groupsHTML = this.renderGroup(this.personalizationConfig)
    const hasPageTheme = this.personalizationConfig.some(instance => instance instanceof PageTheme)

    return `
      <div class="${this.className}">
        <div class="setting-header">
          ${hasPageTheme ? this.renderButton() : ''}
          ${this.getToolbar().render()}
        </div>
        <div class="setting-group-list">
          ${groupsHTML || this.renderNoSetting()}
        </div>
      </div>
    `
  }

  /**
   * 渲染无设置项提示
   */
  private renderNoSetting(): string {
    return `
      <div class="no-setting">
        ${SYMBOLS.NETWORK.LOCK} 未启用个性化
      </div>
    `
  }

  private renderButton(): string {
    return BUTTON_TEMPLATE.download('download-theme-btn', '下载主题样式')
  }

  private getToolbar(): Toolbar {
    if (!this.toolbarInstance) {
      this.toolbarInstance = this.initToolbar()
    }
    return this.toolbarInstance
  }

  private initToolbar(): Toolbar {
    const menus = [
      {
        id: 'personalization-menu',
        icon: SYMBOLS.UI.SETTINGS,
        text: '功能菜单',
        children: [
          { id: 'reset-styles', text: '重置样式', icon: SYMBOLS.OTHERS.PALETTE, onClick: async () => {
            await this.reset(RESET_TYPES.STYLE)
            logger.info(`[${this.name}] 个性化重置完成`)
          } },
          { id: 'reset-inputs', text: '重置输入', icon: SYMBOLS.OTHERS.CLEAR, onClick: async () => {
            await this.reset(RESET_TYPES.INPUT)
            logger.info(`[${this.name}] 输入重置完成`)
          } },
          { id: 'help', text: '使用帮助', icon: SYMBOLS.STATUS.IDEA, title: '推荐先使用广告过滤器屏蔽多余内容，\n再进行个性化设置，可获得最佳视觉效果' },
        ],
      },
    ]
    return new Toolbar({
      id: 'personalization-toolbar',
      menus,
    })
  }

  /**
   * 处理组件打开时的逻辑
   */
  async handleOpen(): Promise<void> {
    await this.initModules()
    const $container = $(`.${this.className}`)
    this.getToolbar().mount($container)

    // 日志下载点击事件
    $container.find('#download-theme-btn').on('click', () => {
      this.downloadTheme()
    })
  }

  /**
   * 下载主题样式
   */
  downloadTheme(): void {
    const themeStyle = document.querySelector(`style#${CustomElementStyleId.ThemeCss}`)
    const themeContent = themeStyle?.textContent || ''

    ToolKit.browser.file.downloadFile(themeContent, {
      filename: `${PROJECT_PREFIX}-主题样式_${ToolKit.time.formatTime(new Date())}.css`,
      type: DownloadFileMimeType.TEXT_CSS,
    })
  }

  /**
   * 渲染设置组
   */
  private renderGroup(group: UserPref[]): string {
    // 1. 渲染所有项
    const itemsHTML = group.map(item => this.renderItem(item)).join('')

    // 2. 按分类重新组织HTML结构
    return this.organizeByCategoryAndPriority(itemsHTML)
  }

  /**
   * 将已包含分类信息的 HTML 按分类重组
   */
  private organizeByCategoryAndPriority(html: string): string {
    const wrapper = document.createElement('div')
    wrapper.innerHTML = html

    // 收集所有设置项元素
    const items = Array.from(wrapper.querySelectorAll('[data-category]'))

    // 创建带权重信息的分类映射
    const categoryMap = new Map<string, {
      elements: Array<{
        element: Element
        priority: number
      }>
      categoryPriority: number // 分类的权重（取最小priority）
    }>()

    items.forEach((item) => {
      const category = item.getAttribute('data-category') || 'default'
      const priority = Number.parseInt(item.getAttribute('data-priority') || '100', 10)

      if (!categoryMap.has(category)) {
        categoryMap.set(category, {
          elements: [],
          categoryPriority: Infinity, // 初始设为最大值
        })
      }

      const categoryData = categoryMap.get(category)!
      categoryData.elements.push({
        element: item,
        priority,
      })

      // 分类权重取所有项中最小的priority
      categoryData.categoryPriority = Math.min(categoryData.categoryPriority, priority)
    })

    // 对分类按权重排序（先按 categoryPriority，再按 category 名称）
    const sortedCategories = [...categoryMap.entries()].sort((a, b) => {
    // 第一排序条件：分类权重
      if (a[1].categoryPriority !== b[1].categoryPriority) {
        return a[1].categoryPriority - b[1].categoryPriority
      }
      // 第二排序条件：分类名称
      return a[0].localeCompare(b[0])
    })

    let resultHTML = ''

    sortedCategories.forEach(([category, categoryData]) => {
      // 分类内按 priority 升序排序
      const sortedItems = categoryData.elements.sort((a, b) => {
      // 第一排序条件：priority
        if (a.priority !== b.priority) {
          return a.priority - b.priority
        }
        // 第二排序条件：data-id
        const aId = a.element.getAttribute('data-type') || ''
        const bId = b.element.getAttribute('data-type') || ''
        return aId.localeCompare(bId)
      })

      resultHTML += this.createCategorySection(
        category as categoryNameType,
        sortedItems.map((item) => {
          const id = item.element.getAttribute('data-id')
          const removeAttributes = ['data-category', 'data-priority', 'data-type', 'data-id']
          removeAttributes.forEach((attr) => {
            item.element.removeAttribute(attr)
          })
          return `
            ${item.element.outerHTML}
            <div class="${this.messageClassName} ${id}"></div>
          `
        }).join(''),
      )
    })
    return resultHTML
  }

  /**
   * 创建分类区块
   */
  private createCategorySection(category: categoryNameType, items: string): string {
    return `
      <div class="setting-group" data-category="${category}">
        <h3 class="${getTitleThemeClassName('PRIMARY', ToolKit.browser.theme.getCurrentTheme())}">${CATEGORY_NAME_CONFIG[category] || '其他设置'}</h3>
        ${items}
      </div>
    `
  }

  /**
   * 处理单个设置项
   */
  private handleItem(item: IPersonalizationItem | IRenderFragment): string {
    const isFragment = 'id' in item && 'html' in item

    const id = item.id
    const type = isFragment ? item.type : (item as IPersonalizationItem).id
    const category = item.category || 'default' // 默认分类
    const priority = item.priority ?? '100' // 默认优先级
    const html = isFragment ? item.html : (item as IPersonalizationItem).render()

    return `
      <div class="setting-item render-${id}" data-category="${category}" data-priority="${priority}" data-type="${type}" data-id="${id}">
        ${!isFragment && (item as IPersonalizationItem).description
          ? `<p class="item-description">${(item as IPersonalizationItem).description}</p>`
          : ''}
        ${html}
      </div>
    `
  }

  /**
   * 渲染设置项
   */
  private renderItem(item: IPersonalizationItem): string {
    const renderResult = item.render()

    if (Array.isArray(renderResult)) {
      return renderResult.map(fragment => this.handleItem(fragment)).join('')
    }
    else {
      return this.handleItem(item)
    }
  }

  /**
   * 获取需要绑定事件的元素
   */
  private getElementsToBind(item: IPersonalizationItem): MountTarget {
    const baseSelector = `.${this.className} .setting-item`

    // 单个组件
    if (item.componentType === 'single') {
      return $(`${baseSelector}.render-${item.id}`)
    }

    // 组件套
    if (item.componentType === 'collection' && item.getInstances) {
      const instances = item.getInstances()
      return Array.from(instances.keys()).map(id => ({
        id,
        element: $(`${baseSelector}.render-${id}`),
      }))
    }

    // 默认回退
    return $(`${baseSelector}[class*="render-${item.id}"]`)
  }

  /**
   * 初始化模块
   */
  private async initModules(): Promise<void> {
    const bindPromises: Promise<void>[] = []

    this.personalizationConfig.forEach((item) => {
      bindPromises.push(
        Promise.resolve()
          .then(() => {
            const elements = this.getElementsToBind(item)
            // 挂载模块
            item.mount(elements)
            logger.debug(`[${this.name}] ${item.id} 事件绑定成功`)
          })
          .catch((error) => {
            logger.error(`[${this.name}] ${item.id} 事件绑定失败:`, error)
            item.initFailed = true
          }),
      )
    })

    try {
      await Promise.all(bindPromises)
      logger.debug(`[${this.name}] 所有事件绑定完成`)
    }
    catch (error: any) {
      logger.error(`[${this.name}] 部分事件绑定失败`, error)
    }
  }

  /**
   * 重置样式
   * @param type 重置类型
   */
  private async reset(type: ResetType): Promise<void> {
    this.personalizationConfig.forEach((item) => {
      if (type === RESET_TYPES.STYLE) {
        // 删除所有个性化存储
        this.storage.deleteBatch()
      }
      item.onReset(type)
    })
  }

  // ================================= 应用样式  =================================
  /**
   * 处理保存逻辑 (返回保存结果和无效项数量)
   */
  async handleSave(): Promise<{ success: boolean, invalidCount: number }> {
    try {
      const results = await Promise.all(
        this.personalizationConfig
          .filter(item => item.onSave)
          .map(item => this.validateAndSave(item)),
      )

      return {
        success: true,
        invalidCount: results.reduce((sum, count) => sum + count, 0),
      }
    }
    catch (error: any) {
      logger.error(`[${this.name}] 保存过程中出错: ${error.message}`)
      return { success: false, invalidCount: 0 }
    }
  }

  /**
   * 验证并执行保存操作
   * @returns 无效项数量
   */
  private validateAndSave(item: UserPref): number {
    const checkIds = item.componentType === 'collection'
      ? item.getInstanceIds()
      : [item.id]

    // 调试信息收集
    const validationReport = {
      componentId: item.id,
      checkIds,
      missingSelectors: [] as string[],
      invalidSelectors: [] as string[],
    }

    // 检查元素存在性
    const existingItems = checkIds.filter((id: string) => {
      const selector = `.${this.className} .setting-item.render-${id}`
      const exists = $(selector).length > 0
      if (!exists)
        validationReport.missingSelectors.push(selector)
      return exists
    })

    if (validationReport.missingSelectors.length > 0) {
      logger.warn(`[${this.name}] 设置项缺失报告:`, validationReport)
      return 0
    }

    // 执行保存
    item.onSave!() // 使用非空断言

    // 检查无效项
    existingItems.forEach((id: string) => {
      const selector = `.${this.className} .setting-item.render-${id}`
      if ($(selector).hasClass(ITEM_STATE.INVALID.className)) {
        validationReport.invalidSelectors.push(selector)
      }
      this.updateSettingsStatus(item, $(selector), id)
    })

    if (validationReport.invalidSelectors.length > 0) {
      logger.info(`[${this.name}] 无效项报告:`, validationReport)
    }

    return validationReport.invalidSelectors.length
  }

  /**
   * 更新设置项状态
   */
  updateSettingsStatus(instance: UserPref, container: JQuery<HTMLElement>, id: string): void {
    const valid = !container.hasClass(ITEM_STATE.INVALID.className)
    const storageSaved = instance.getStorageValues(id).saved
    const saved = storageSaved && valid

    container
      .attr(ITEM_STATE.SAVED.attributes!, `${saved}`)
      .addClass(saved ? ITEM_STATE.SAVED.className : '')
      .removeClass(ITEM_STATE.CHANGED.className)
  }

  // ================================= 组件样式  =================================
  styles(): string {
    return `
      .${this.className} {
        all: initial !important;
        display: flex;
        flex-direction: column;
        gap: 20px;
        width: 100%;
        max-width: 800px;
        margin: 0 auto;
        color: #333;
      }
      
      /* 设置头样式 */
      .setting-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 10px;
        
        ${BUTTON_TEMPLATE_STYLES.download}
      }
      
      /* 设置组列表样式 */
      .setting-group-list {
        display: flex;
        flex-direction: column;
        gap: 25px;
        border-radius: 8px;
        
        .no-setting {
          color: var(${this.themeVarService.message.orange.textPrimary}) !important;
          text-align: center !important;
        }
      }
      
      /* 设置组样式 */
      .setting-group {
        display: flex;
        flex-direction: column;
        gap: 15px;
        padding: 0 0 10px 0;
        background-color: var(--${PROJECT_PREFIX}-theme-bg-base) !important;
        border-radius: 8px;
        border: 1px solid var(--${PROJECT_PREFIX}-theme-border-primary) !important;
      }
      
      /* 设置项消息样式 */
      .${this.messageClassName} {
        all: initial !important; /* 重置所有样式 */
        display: none;
        padding: 0;
        margin: 0;
        width: 0;
        height: 0;
        border-radius: 4px !important;
        font-size: 12px !important;
        animation: fadeIn 0.3s ease-in-out !important;
      }
      
      /* 分类区块样式 */
      .category-section {}
      
      .category-title {
        padding: 0.75rem 1rem;
        margin: 0;
        background-color: #f6f8fa;
        font-size: 0.95rem;
        border-bottom: 1px solid #e1e4e8;
      }
      
      .category-content {
        padding: 1rem;
        display: grid;
        gap: 1rem;
      }
      
      /* 设置项样式 */
      .setting-item {
        all: initial;
        position: relative; /* 添加相对定位 */
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 5px;
        border: 1.5px solid transparent;
        padding: 10px 10px 10px 18px !important; /* 左侧增加内边距为伪元素留空间 */
        /* 统一伪元素样式 */
        &::before {
          content: "";
          position: absolute;
          left: 5px;
          top: 50%;
          transform: translateY(-50%);
          font-size: 14px;
          margin-right: 0;
        }
        h4, label {
          display: inline-block;
          font-size: 15px;
          color: var(--${PROJECT_PREFIX}-theme-text-secondary) !important;
          font-weight: 500 !important;
          min-width: 100px;
          white-space: nowrap;
        }
        .custom-text-input,
        .custom-range-slider,
        .custom-select {
          flex: 1;
          min-width: 0;
        }
      }
      /* 保存状态 */
      .setting-item.${ITEM_STATE.SAVED.className}::before {
        content: "${SYMBOLS.SHAPES.CIRCLE}";
        color: ${ITEM_STATE.SAVED.color};
      }
      /* 变更状态 */
      .setting-item.${ITEM_STATE.CHANGED.className}::before {
        content: "${SYMBOLS.SHAPES.CIRCLE}";
        color: ${ITEM_STATE.CHANGED.color};
      }
      /* 无效状态 */
      .setting-item.${ITEM_STATE.INVALID.className} {
        animation: invalidShake 0.5s ease-in-out;
        &::before {
          content: "${SYMBOLS.SHAPES.CIRCLE}";
          color: ${ITEM_STATE.INVALID.color};
        }
      }
      /* 变更状态优先于保存状态 */
      .setting-item.${ITEM_STATE.CHANGED.className}.${ITEM_STATE.SAVED.className}::before {
          color: ${ITEM_STATE.CHANGED.color};
      }

      .actions {
        all: initial;
        display: flex;
        justify-content: center;
        margin-top: 20px;
        
        .btn {
          all: initial;
          display: inline-block;
          padding: 8px 16px;
          margin: 15px;
          font-size: 14px;
          font-weight: 500;
          line-height: 1.5;
          text-align: center;
          white-space: nowrap;
          vertical-align: middle;
          cursor: pointer;
          border-radius: 6px;
          transition: all 0.2s ease;
          user-select: none;
          border: 1px solid transparent;
        }
      }
      
      /* 响应式调整 */
      @media (max-width: 768px) {
        .setting-item {
          flex-direction: column;
          align-items: flex-start;
          gap: 8px;
          
          label {
            margin-right: 0;
            margin-bottom: 5px;
          }
        }
      }
    `
  }
}
